#
# A suite of tests for bash word expansions
#
# This tests parameter and variable expansion, with an empahsis on
# proper quoting behavior.
#
# Chet Ramey

#
# If you comment out the body of this function, you can do a diff against
# `expansion-tests.right' to see if the shell is behaving correctly
#
expect()
{
	echo expect "$@"
}

# Test the substitution quoting characters (CTLESC and CTLNUL) in different
# combinations

expect "<^A>"
recho `echo ''`
expect "<^A>"
recho `echo ""`
expect "<^?>"
recho `echo ''`
expect "<^?>"
recho `echo ""`
expect "<^A>"
recho `echo `
expect "<^?>"
recho `echo `

expect "bar"
recho ${foo:-"`echo bar`"}
expect "<^A>"
recho ${foo:-"`echo `"}
expect "<^?>"
recho ${foo:-"`echo `"}

expect "<^A>"
recho "`echo `"
expect "<^?>"
recho "`echo `"

# Test null strings without variable expansion
expect "<abcdefgh>"
recho abcd""efgh
expect "<abcdefgh>"
recho abcd''efgh
expect "<abcdefgh>"
recho ""abcdefgh
expect "<abcdefgh>"
recho ''abcdefgh
expect "<abcd>"
recho abcd""
expect "<abcd>"
recho abcd''

# Test the quirky behavior of $@ in ""
expect nothing
recho "$@"
expect "< >"
recho " $@"
expect "<-->"
recho "-${@}-"

# Test null strings with variable expansion that fails
expect '<>'
recho $xxx""
expect '<>'
recho ""$xxx
expect '<>'
recho $xxx''
expect '<>'
recho ''$xxx
expect '<>'
recho $xxx""$yyy
expect '<>'
recho $xxx''$yyy

# Test null strings with variable expansion that succeeds
xxx=abc
yyy=def

expect '<abc>'
recho $xxx""
expect '<abc>'
recho ""$xxx
expect '<abc>'
recho $xxx''
expect '<abc>'
recho ''$xxx
expect '<abcdef>'
recho $xxx""$yyy
expect '<abcdef>'
recho $xxx''$yyy

unset xxx yyy

# Test the unquoted special quoting characters
expect "<^A>"
recho 
expect "<^?>"
recho 
expect "<^A>"
recho ""
expect "<^?>"
recho ""
expect "<^A>"
recho ''
expect "<^?>"
recho ''

# Test expansion of a variable that is unset
expect nothing
recho $xxx
expect '<>'
recho "$xxx"

expect nothing
recho "$xxx${@}"

# Test empty string expansion
expect '<>'
recho ""
expect '<>'
recho ''

# Test command substitution with (disabled) history substitution
expect '<Hello World!>'
# set +H
recho "`echo \"Hello world!\"`"

# Test some shell special characters
expect '<`>'
recho "\`"
expect '<">'
recho "\""
expect '<\^A>'
recho "\"

expect '<\$>'
recho "\\$"

expect '<\\>'
recho "\\\\"

# This should give argv[1] = a argv[2] = b
expect '<a> <b>'
FOO=`echo 'a b' | tr ' ' '\012'`
recho $FOO

# This should give argv[1] = ^A argv[2] = ^?
expect '<^A> <^?>'
FOO=`echo ' ' | tr ' ' '\012'`
recho $FOO

# Test quoted and unquoted globbing characters
expect '<**>'
recho "*"*

expect '<\.\./*/>'
recho "\.\./*/"

# Test patterns that come up when the shell quotes funny character
# combinations
expect '<^A^?^A^?>'
recho ''
expect '<^A^A>'
recho ''
expect '<^A^?>'
recho ''
expect '<^A^A^?>'
recho ''

# More tests of "$@"
set abc def ghi jkl
expect '<  abc> <def> <ghi> <jkl  >'
recho "  $@  "
expect '<  abc> <def> <ghi> <jkl  >'
recho "${1+  $@  }"

set abc def ghi jkl
expect '<--abc> <def> <ghi> <jkl-->'
recho "--$@--"

set "a b" cd ef gh
expect '<a b> <cd> <ef> <gh>'
recho ${1+"$@"}
expect '<a b> <cd> <ef> <gh>'
recho ${foo:-"$@"}
expect '<a b> <cd> <ef> <gh>'
recho "${@}"

expect '<  >'
recho "  "
expect '< - >'
recho " - "

# Test combinations of different types of quoting in a fully-quoted string
# (so the WHOLLY_QUOTED tests fail and it doesn't get set)
expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>'
recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/"

# Test the various Posix parameter expansions

expect '<foo bar>'
recho "${x:-$(echo "foo bar")}"
expect '<foo> <bar>'
recho ${x:-$(echo "foo bar")}

unset X
expect '<abc>'
recho ${X:=abc}
expect '<abc>'
recho $X

set a b c
expect '<posix>'
recho ${3:+posix}

POSIX=/usr/posix
expect '<10>'
recho ${#POSIX}

# remove shortest trailing match
x=file.c
expect '<file.o>'
recho ${x%.c}.o

# remove longest trailing match
x=posix/src/std
expect '<posix>'
recho ${x%%/*}

# remove shortest leading pattern
x=$HOME/src/cmd
expect '</src/cmd>'
recho ${x#$HOME}

# remove longest leading pattern
x=/one/two/three
expect '<three>'
recho ${x##*/}

# pattern removal of patterns that don't match
z=abcdef

expect '<abcdef>'
recho ${z#xyz}
expect '<abcdef>'
recho ${z##xyz}

expect '<abcdef>'
recho ${z%xyz}
expect '<abcdef>'
recho ${z%%xyz}

# Command substitution and the quirky differences between `` and $()

expect '<\$x>'
recho '\$x'

expect '<$x>'
recho `echo '\$x'`

expect '<\$x>'
recho $(echo '\$x')

# The difference between $* "$*" and "$@"

set "abc" "def ghi" "jkl"

expect '<abc> <def> <ghi> <jkl>'
recho $*

expect '<abc def ghi jkl>'
recho "$*"

OIFS="$IFS"
IFS=":$IFS"

# The special behavior of "$*", using the first character of $IFS as separator
expect '<abc:def ghi:jkl>'
recho "$*"

IFS="$OIFS"

expect '<abc> <def ghi> <jkl>'
recho "$@"

expect '<xxabc> <def ghi> <jklyy>'
recho "xx$@yy"

expect '<abc> <def ghi> <jklabc> <def ghi> <jkl>'
recho "$@$@"

foo=abc
bar=def

expect '<abcdef>'
recho "$foo""$bar"

unset foo
set $foo bar '' xyz "$foo" abc

expect '<bar> <> <xyz> <> <abc>'
recho "$@"

# More tests of quoting and deferred evaluation

foo=10 x=foo
y='$'$x
expect '<$foo>'
recho $y
eval y='$'$x
expect '<10>'
recho $y

# case statements

NL='
'
x='ab
cd'

expect '<newline expected>'
case "$x" in
*$NL*)	recho "newline expected" ;;
esac

expect '<got it>'
case \? in
*"?"*) recho "got it" ;;
esac

expect '<got it>'
case \? in
*\?*) recho "got it" ;;
esac

set one two three four five
expect '<one> <three> <five>'
recho $1 $3 ${5} $8 ${9}

# length tests on positional parameters and some special parameters

expect '<5> <5>'
recho $# ${#}
expect '<3>'
recho ${#1}
expect '<1>'
recho ${##}
expect '<1>'
recho ${#?}
expect '<5>'
recho ${#@}
expect '<5>'
recho ${#*}
expect '<5>'
recho "${#@}"
expect '<5>'
recho "${#*}"

expect '<42>'
recho $((28 + 14))
expect '<26>'
recho $[ 13 * 2 ]

expect '<\>'
recho `echo \\\\`

expect '<~>'
recho '~'

expect nothing
recho $!
expect nothing
recho ${!}

# test word splitting of assignment statements not preceding a command
a="a b c d e"
declare b=$a
expect '<a> <b> <c> <d> <e>'
recho $b

a="a?b?c"

echo ${a//\\?/ }

echo ${a//\?/ }

${THIS_SH} ./exp1.sub

${THIS_SH} ./exp2.sub

${THIS_SH} ./exp3.sub

${THIS_SH} ./exp4.sub

${THIS_SH} ./exp5.sub

${THIS_SH} ./exp6.sub
${THIS_SH} ./exp7.sub
${THIS_SH} ./exp8.sub
${THIS_SH} ./exp9.sub
${THIS_SH} ./exp10.sub
${THIS_SH} ./exp11.sub
${THIS_SH} ./exp12.sub
